package service

import (
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	_ "hash/fnv"
	"medical/abac"
	"medical/sdkInit"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/hyperledger/fabric-protos-go/common"

	_ "github.com/go-sql-driver/mysql" //初始化
	"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/ledger"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
)

/*
//记录当日初始区块和结束区块
type BlockNum struct {
	StartBlockNum int
	EndBlockNum   int
}

//按照年月日划分节点
type RecordTree struct {
	Num   *BlockNum
	Val   int
	Sub   []RecordTree
	Level int
	Leaf  bool
}

//按年、月日查询，使用二分查找
func BinarySearch(arr []RecordTree, target int) int {
	if len(arr) == 0 {
		return -1
	}
	if arr[0].Leaf {
		return -1
	}
	l, r, m := 0, len(arr), 0
	for l <= r {
		m = l + (r-l)/2
		if arr[m].Val > target {
			r = m - 1
		} else if arr[m].Val < target {
			l = m + 1
		} else {
			return m
		}
	}
	return -1
}
*/

// 写到服务层里面，所有字段用于和数据库对接（服务层调用数据库和链码）
type MedicalRecord struct {
	Groups         string `json:"groups"`         //分组
	SubjectMark    string `json:"subjectMark"`    //样本标识符
	Name           string `json:"name"`           //姓名
	NameInitials   string `json:"nameInitials"`   //姓名缩写
	CaseNumber     string `json:"caseNumber"`     //病例号，并上链
	Sex            string `json:"sex"`            //性别
	Nation         string `json:"nation"`         //民族
	Diseases       string `json:"diseases"`       //疾病种类
	MedicalHistory string `json:"medicalHistory"` //现病史
	NativePlace    string `json:"nativePlace"`    //现住地
	Diagnose       string `json:"diagnose"`       //诊断
	Researcher     string `json:"researcher"`     //研究者，并上链
	Organization   string `json:"organization"`   //机构，并上链
	Addition1      string `json:"addition1"`      //预留信息
	Addition2      string `json:"addition2"`      //预留信息
	Addition3      string `json:"addition3"`      //预留信息
	Status         string `json:"status"`         //状态
	EntryTime      string `json:"entryTime"`      //入组时间
	BaseTime       string `json:"baseTime"`       //基准时间
	GatherTime     string `json:"gatherTime"`     //采集时间-1，并上链
}

type OperationRecordArr struct {
	OperationRecord []OperationRecord
}

// 只保留上链字段，与链码中相同
type MedicalRecordForChain struct {
	CaseNumber      string `json:"caseNumber"`      //病例号，上链
	Researcher      string `json:"researcher"`      //研究者，上链
	Organization    string `json:"organization"`    //机构，上链
	OperationType   string `json:"operationType"`   //操作类型
	OperationResult string `json:"operationResult"` //操作结果
	GatherTime      string `json:"gatherTime"`      //采集时间-1，上链
}

// 医疗记录修改历史
type MedicalRecordHistory struct {
	Txid     string                //交易ID
	Txvalue  MedicalRecordForChain //病例当时的值
	Txstatus string                //状态：是否被删除
	Txtime   string                //修改时间
}

type MedicalRecordHistoryArr struct {
	MRH []MedicalRecordHistory `json:"medicalRecordHistory"` //用数组保存
}

// 只留三条区块信息
type GetThisBlockInto struct {
	FirstBlock  Block // 最新
	SecondBlock Block
	ThirdBlock  Block
}

// 区块编号,区块哈希,时间,操作类型,操作人员ID,针对对象ID
type Block struct {
	NumberBlock  string `json:"numberBlock"`
	HashBlock    string `json:"hashBlock"`
	GenerateTime string `json:"time"`
	ActionType   string `json:"actionType"`
	ObjectID     string `json:"objectID"`
	SubjectID    string `json:"subjectID"`
}

// 表格的每一行
type TableRow struct {
	FirstColumn   string
	SecondColumn  string
	ThirdColumn   string
	FourthColumn  string
	FifthColumn   string
	SixthColumn   string
	SeventhColumn string
}

// 操作记录，记录在区块链上不可被修改
type OperationRecord struct {
	OperationRecordID string `json:"operationRecordId"` //操作记录ID
	UserID            string `json:"userId"`            //操作者用户
	OrganizationID    string `json:"organizationID"`    //用户组织ID
	DataType          string `json:"dataType"`          //记录类型：操作记录operation
	ActionType        string `json:"actionType"`        //操作类型：访问、修改、删除（Access、Update、Delete）
	MedicalRecordID   string `json:"medicalRecordId"`   //涉及到的医疗记录ID
	OriginalAuthorID  string `json:"originalAuthorId"`  //涉及到的医疗记录创建者
	PatientID         string `json:"patientId"`         //医疗记录涉及到的患者ID
	EntryMethod       string `json:"entryMethod"`       //操作记录的输入方式：自动输入
	IsSuccess         bool   `json:"isSuccess"`         //*新增：操作是否成功，成功为True
	Time              string `json:"time"`              //时间
}

// 审计记录，记录在区块链上不可被修改
type AuditRecord struct {
	AuditRecordID  string `json:"auditRecordId"`  //审计记录ID
	UserID         string `json:"userId"`         //操作者用户（此处为管理员）
	OrganizationID string `json:"organizationID"` //用户组织ID
	DataType       string `json:"dataType"`       //记录类型：审计Audit
	EntryMethod    string `json:"entryMethod"`    //审计记录的输入方式：自动输入
	Time           string `json:"time"`           //时间
}

// *新增：审计报告，记录组织的失败率信息
type AuditReport struct {
	AuditorName     string     `json:"auditorName"`     //审计者姓名
	TargetOrg       string     `json:"targetOrg"`       //被审计组织ID
	CurrentCredit   float64    `json:"currentCredit"`   //组织现在的信誉值
	PreviousCredit  float64    `json:"previousCredit"`  //组织之前的信誉值
	CreditChange    string     `json:"creditChange"`    //组织信誉值变动情况：上升、下降、不变
	ReferenceRange  [2]float64 `json:"referenceRange"`  //参照区间
	TotalOperations int64      `json:"totalOperations"` //组织总操作次数
	FailOperations  int64      `json:"failOperations"`  //组织失败操作次数
	FailRate        float64    `json:"failRate"`        //组织失败操作率
	MaxFailRateUser string     `json:"maxFailRateUser"` //组织中失败率最高的用户ID
	MaxFailRate     float64    `json:"maxFailRate"`     //组织所有用户中最高的失败率
}

type ServiceSetup struct {
	ChaincodeID string
	Client      *channel.Client
	c           *ledger.Client
}

// 数据库配置
const (
	userName = "root"
	password = "root"
	ip       = "127.0.0.1"
	port     = "3306"
	dbName   = "itbtsql"
)

type showData struct {
	BlockNumber string
	BlockHash   string
	chainCode   string
	Txid        string
	data        justdata
}
type justdata struct {
	sig       string
	sigdata   sigdata
	result    string
	judgetime string
}
type sigdata struct {
	obj    string
	user   string
	insti  string
	action string
	time   string
}

var weight = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
var valid_value = [11]byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
var valid_province = map[string]string{
	"11": "北京市",
	"12": "天津市",
	"13": "河北省",
	"14": "山西省",
	"15": "内蒙古自治区",
	"21": "辽宁省",
	"22": "吉林省",
	"23": "黑龙江省",
	"31": "上海市",
	"32": "江苏省",
	"33": "浙江省",
	"34": "安徽省",
	"35": "福建省",
	"36": "江西省",
	"37": "山东省",
	"41": "河南省",
	"42": "湖北省",
	"43": "湖南省",
	"44": "广东省",
	"45": "广西壮族自治区",
	"46": "海南省",
	"50": "重庆市",
	"51": "四川省",
	"52": "贵州省",
	"53": "云南省",
	"54": "西藏自治区",
	"61": "陕西省",
	"62": "甘肃省",
	"63": "青海省",
	"64": "宁夏回族自治区",
	"65": "新疆维吾尔自治区",
	"71": "台湾省",
	"81": "香港特别行政区",
	"91": "澳门特别行政区",
}

// Db数据库连接池
var DB *sql.DB

//// 查看交易所在区块
//func GetBlockByTxID(c *ledger.Client, txID fab.TransactionID) {
//	fmt.Println(c.QueryBlockByTxID(txID))
//}

func regitserEvent(client *channel.Client, chaincodeID, eventID string) (fab.Registration, <-chan *fab.CCEvent) {

	reg, notifier, err := client.RegisterChaincodeEvent(chaincodeID, eventID)
	if err != nil {
		fmt.Println("注册链码事件失败: %s", err)
	}
	return reg, notifier
}

func eventResult(notifier <-chan *fab.CCEvent, eventID string) error {
	select {
	case ccEvent := <-notifier:
		fmt.Printf("接收到链码事件: %v\n", ccEvent)
	case <-time.After(time.Second * 20):
		return fmt.Errorf("不能根据指定的事件ID接收到相应的链码事件(%s)", eventID)
	}
	return nil
}

func InitService(chaincodeID, channelID string, org *sdkInit.OrgInfo, sdk *fabsdk.FabricSDK) (*ServiceSetup, error) {
	handler := &ServiceSetup{
		ChaincodeID: chaincodeID,
	}
	//prepare channel client context using client context
	clientChannelContext := sdk.ChannelContext(channelID, fabsdk.WithUser(org.OrgUser), fabsdk.WithOrg(org.OrgName))
	// Channel client is used to query and execute transactions (Org1 is default org)
	client, err := channel.New(clientChannelContext)
	if err != nil {
		return nil, fmt.Errorf("Failed to create new channel client: %s", err)
	}
	handler.Client = client
	// 添加对ledger的声明，用于获取block信息
	// By J 230310
	blockcc, err2 := ledger.New(clientChannelContext)
	if err2 != nil {
		return nil, fmt.Errorf("Failed to create new ledger client: %s", err)
	}
	handler.c = blockcc
	return handler, nil
}

// 注意方法名大写，就是public
func InitDB() *sql.DB {
	//构建连接："用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
	path := userName + ":" + password + "@tcp(" + ip + ":" + port + ")/" + dbName + "?allowNativePasswords=true"
	fmt.Println(path)
	//打开数据库,前者是驱动名，所以要导入： _ "github.com/go-sql-driver/mysql"
	DB, _ = sql.Open("mysql", path)
	//设置数据库最大连接数
	DB.SetConnMaxLifetime(100)
	//设置上数据库最大闲置连接数
	DB.SetMaxIdleConns(10)
	//验证连接
	if err := DB.Ping(); err != nil {
		fmt.Println("open database fail")
		fmt.Println(err)
	}
	fmt.Println("connnect success")
	return DB
}

// 用于生成sql查询语句
func SetSQL(sqlmap interface{}, queryString string) string {
	temp := sqlmap.(map[int]string)
	for k := range temp {
		fmt.Println(k, temp[k])
	}
	// "SELECT _SubjectMark From baseinfo WHERE _Groups='喹硫平'"
	// 可自行更改字段
	sql := "SELECT " + temp[1] + " From " + temp[0] + " WHERE " + temp[2] + "='" + queryString + "'"
	fmt.Println(sql)
	return sql
}

// 查询并返回数据 -> 替换为 AdvanceQuery(DB *sql.DB, Sql string) map[int]string
func queryDB(DB *sql.DB, Sql string) map[int]string {
	var subId string
	rows, err := DB.Query(Sql)
	if err != nil {
		fmt.Println(err)
	}
	data := make(map[int]string)
	index := 0
	for rows.Next() {
		rows.Scan(&subId)
		data[index] = subId
		index = index + 1
		//fmt.Println(subId)
	}
	defer rows.Close()
	return data
}

// 参考 https://blog.csdn.net/rockage/article/details/103776251 更改
// 传参为sql语句，返回 map[int]string 用法与 queryDB() 一致
// 原始结果
// [map[_CaseNumber:78bb66a06c79f _Diseases:神经系统疾病 _GatherTime:2022-09-22 17:31:24 _Organization:北大六院 _Researcher:张三 _SubjectMark:9359-48148 n:53]]
// 更改完 map[0:1 1:0060-55698 2:李四 3:北大六院 4:神经系统疾病 5:72d560a776a77 6:2022-09-22 17:31:24]
func AdvanceQuery(DB *sql.DB, SQL string) map[int]string { //通用查询
	rows, err := DB.Query(SQL) //执行SQL语句，比如select * from users
	if err != nil {
		panic(err)
	}
	columns, _ := rows.Columns()            //获取列的信息
	count := len(columns)                   //列的数量
	var values = make([]interface{}, count) //创建一个与列的数量相当的空接口
	for i, _ := range values {
		var ii interface{} //为空接口分配内存
		values[i] = &ii    //取得这些内存的指针，因后继的Scan函数只接受指针
	}
	index := 0
	data := make(map[int]string) //用于存放1列的 [键/值] 对
	for rows.Next() {
		err := rows.Scan(values...) //开始读行，Scan函数只接受指针变量

		if err != nil {
			panic(err)
		}
		// colName 为列字段
		// for i, colName := range columns
		for i, _ := range columns {
			var raw_value = *(values[i].(*interface{})) //读出raw数据，类型为byte
			b, _ := raw_value.([]byte)
			v := string(b)  //将raw数据转换成字符串
			data[index] = v //colName是键，v是值
			index = index + 1
		}
	}

	defer rows.Close()

	if len(data) != 0 {
		return data
	}
	return nil
}

func InsertDBOperation(DB *sql.DB, DataType string, ActionType string) {
	// UserID string; MedicalRecordID string; DataType 'med','医疗记录','策略信息','审计日志','溯源结果'
	// ActionType '创建','更新','查看','访问','删除'
	// IsSuccess 'T','F' ; IsUpload 'T','F' ; _GatherTime time
}

func InsertDB(DB *sql.DB, data []string, casenumber string) bool {
	sqlString := "insert ignore into base_info(_Groups,_SubjectMark,_Name,_NameInitials,_CaseNumber,_Sex,_Nation,_Diseases,_MedicalHistory,_NativePlace,_Diagnose,_Researcher,_Organization,_Addition1,_Addition2,_Addition3,_Status,_EntryTime,_BaseTime,_GatherTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
	r, err0 := DB.Exec(sqlString, data[0], data[1], data[2], data[3], casenumber, data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02 15:04:05"))
	if err0 != nil {
		fmt.Println("插入失败：", err0)
		return false
	}
	id, err1 := r.LastInsertId()
	if err1 != nil {
		fmt.Println("操作失败：", err1)
		return false
	}
	fmt.Println("插入成功：", id)
	//受影响的行数
	row_affect, err2 := r.RowsAffected()
	if err2 != nil {
		fmt.Println("受影响行数获取失败:", err2)
		return false
	}
	fmt.Println("受影响的行数：", row_affect)
	return true
}

// 根据各种信息生成CaseNumber的函数，暂时没想好怎么写
// 函数冗余，直接调用 sqlaction.GetCaseNumber 即可 By J 0301
func GenerateCaseNumber(data []string) string {
	//共有6个参数，分别为机构、类型、Subject、病种、所属人、时间
	if len(data) != 6 {
		return ""
	}
	final_casenumber := ""
	//以下为编号的顺序
	//机构码为4位
	orgID := "0001" //换算方式另讨论
	final_casenumber += orgID
	//操作类型占2位，UploadMedical为00，UpdateMedical为01，DeleteMedical为02，AccessMedical为03
	m := map[string]string{
		"UploadMedical": "00",
		"UpdateMedical": "01",
		"DeleteMedical": "02",
		"AccessMedical": "03",
	}
	v, flag := m[data[1]]
	if flag {
		final_casenumber += v
	} else {
		return ""
	}
	//Subject为3位
	subjectID := "001"
	final_casenumber += subjectID
	//病种为3位
	diseaseID := "001"
	final_casenumber += diseaseID
	//所属人ID为4位
	final_casenumber += data[4]
	//时间为8位，前4位为年、后2位为月、最后2位为日
	final_casenumber += data[5][:3] + data[5][5:7] + data[5][8:10]
	return final_casenumber //返回最终生成的CaseNumber，一共为4+2+3+3+4+8=24位
}

// 将与区块链相关的数据先存到数据库中，在GenerateCaseNumber，返回casenumber和操作结果
func InsertChainBasedDataIntoDB(DB *sql.DB, data []string) (string, bool) {
	if len(data) != 5 {
		return "", false
	}
	tn := time.Now()
	d := []string{data[4], data[0], data[1], data[2], data[3], tn.Format("2006-01-02")}
	case_number := GenerateCaseNumber(d)
	if len(case_number) != 24 {
		return "", false
	}
	sqlString := "insert into chain_based_data(_CaseNumber,_ActionType,_Subject,_DiseaseType,_PatientNumber,_OrgNumber,_Time) values(?, ?, ?, ?, ?, ?, ?);"
	r, err0 := DB.Exec(sqlString, case_number, data[0], data[1], data[2], data[3], data[4], tn.Format("2006-01-02 15:04:05"))
	if err0 != nil {
		fmt.Println("插入失败：", err0)
		return "", false
	}
	id, err1 := r.LastInsertId()
	if err1 != nil {
		fmt.Println("操作失败：", err1)
		return "", false
	}
	fmt.Println("插入成功：", id)
	//受影响的行数
	row_affect, err2 := r.RowsAffected()
	if err2 != nil {
		fmt.Println("受影响行数获取失败:", err2)
		return "", false
	}
	fmt.Println("受影响的行数：", row_affect)
	return case_number, true
}

func InitPolicy(DB *sql.DB, casenumber string) string {
	var g, s, d, r, o, t string
	rows := DB.QueryRow("select _Groups,_SubjectMark,_Diseases,_Researcher,_Organization,_GatherTime FROM base_info where _CaseNumber='" + casenumber + "'")
	rows.Scan(&g, &s, &d, &r, &o, &t)
	// result := make(map[int]string)
	// result = queryDB(DB, "select insti_name from insti_coop where _CaseNumber='"+casenumber+"'")
	// for _, v := range result {
	// 	o = o + " " + v
	// }
	attr := abac.Date2DB{
		Groups:       g,
		SubjectMark:  s,
		Diseases:     d,
		Researcher:   r,
		Organization: o,
	}
	policy := abac.InitPolicyCreate(abac.Date2DB(attr), casenumber, t)
	var str string
	SQLString := "select * from policy where policy_id='" + casenumber + "'"
	err := DB.QueryRow(SQLString).Scan(&str)
	if err == sql.ErrNoRows { //没有结果
		SQLString3 := "insert into policy(policy_id,policy_data)values(?,?)"
		_, err := DB.Exec(SQLString3, casenumber, policy)
		if err != nil {
			fmt.Println("err")
		}
	}
	return policy
}

func UpdataPolicy(DB *sql.DB, oldPolicy abac.Policy, args []string) string {

	// action :=
	// var newpolicy abac.Policy
	newPolicy := oldPolicy

	newPolicy.Env.CreatedTime = args[0]
	newPolicy.Env.EndTime = args[1]
	// org_list := []string{"北大六院", "北京天坛医院", "天津医科大学附属医院", "山东大学齐鲁医院"}
	allowOrg := ""
	fmt.Println("the org list is ", args[0], args[1], args[2], args[3], args[4], args[5], args[6])
	for i := 2; i < 6; i++ {
		if args[i] != "" {
			fmt.Println(args[i])
			allowOrg += args[i]
			if i < 5 {
				allowOrg += ";"
			}
		}
	}
	fmt.Println("the allowOrg is ", allowOrg)

	newPolicy.Env.AllowOrg = allowOrg

	subRules := newPolicy.SubRules
	action_list := []string{"r", "w", "d"}
	// newRules := []string{}
	for k, v := range subRules {
		// TODO：对rule的解析可以改进
		// fmt.Println("k is ", k, "and v is ", v)
		onerule := strings.Split(v, ",")
		v = ""
		for m, n := range onerule {
			kv := strings.Split(n, ":")
			if kv[0] == "action" {
				kv[1] = ""
				// 三种行为
				for i := 0; i < 3; i++ {
					if args[3*k+i+6] != "" {
						kv[1] += action_list[i]
					}
				}
			}
			onerule[m] = kv[0] + ":" + kv[1]
			v += onerule[m]
			if m < len(onerule)-1 {
				v += ","
			}
		}
		subRules[k] = v
		// err := json.Unmarshal([]byte(v), &onerule)
		// if err != nil {
		fmt.Println("k is ", k, "and v is ", v)
		// onerule["action"] = ""

		// }
		// subRule_byte, err := json.Marshal(onerule)
		// subRules[k] = string(subRule_byte)
	}
	newPolicy.SubRules = subRules

	policy_str, _ := json.Marshal(newPolicy)
	policy := string(policy_str)
	// policy := abac.UpdataPolicyCreate(abac.Date2DB(attr), casenumber, t)

	// if len(actions_arg) > 0 {
	// 	actions := actions_arg[0]
	// 	policy = abac.AutoPolicyCreate(abac.Date2DB(attr), casenumber, args[5], actions)

	// } else {
	// 	policy = abac.AutoPolicyCreate(abac.Date2DB(attr), casenumber, args[5])

	// }
	// SQLString := "select * from policy where policy_id='" + casenumber + "'"
	// err := DB.QueryRow(SQLString).Scan(&str)
	// if err == sql.ErrNoRows { //没有结果
	// 	SQLString3 := "insert into policy(policy_id,policy_data)values(?,?)"
	// 	_, err := DB.Exec(SQLString3, casenumber, policy)
	// 	if err != nil {
	// 		fmt.Println("err")
	// 	}
	// }
	return policy
}

func CheckAction(DB *sql.DB, casenumber string, action string) (bool, string) {

	var uid, username string
	SQLString := "select usertype,username from login where state='1'"
	err := DB.QueryRow(SQLString).Scan(&uid, &username)
	if err != nil { //没有结果
		fmt.Println("err, can't find logined user")
		return false, ""
	}
	var req abac.ABACRequest
	req.Obj = casenumber
	req.Op = action
	req.Sub = uid

	var user abac.Sub
	// user.UID = uid
	// var user_info string
	SQLString = "select * from user_type where user_id='" + uid + "'"
	err = DB.QueryRow(SQLString).Scan(&user.UID, &user.Role, &user.Org, &user.Group)
	if err == sql.ErrNoRows { //没有结果
		fmt.Println("err, can't find the user's information.")
		return false, "您未设置您的属性"
	}
	// fmt.Println("user is ", user.UID, user.Role, user.Org, user.Group)

	var policy string
	SQLString = "select policy_data from policy where policy_id='" + casenumber + "'"
	_ = DB.QueryRow(SQLString).Scan(&policy)
	// fmt.Println("policy is ", policy)

	// 3.0 check是否为owner
	var researcher, organization, diseases string
	SQLString = "select _Researcher,_Organization,_Diseases from base_info where _CaseNumber='" + casenumber + "'"
	_ = DB.QueryRow(SQLString).Scan(&researcher, &organization, &diseases)
	if researcher == username && organization == user.Org && diseases == user.Group {
		return true, "可正常访问"
	}
	f, result := abac.CheckAccess(req, policy, user)
	return f, result
}

func SelectDBSingle(DB *sql.DB, casenumer string) bool {
	sqlString := "select * from base_info where _CaseNumber = ?"
	stmt, _ := DB.Prepare(sqlString)
	row := stmt.QueryRow(casenumer)
	if row == nil {
		fmt.Println("未获取到该记录:", casenumer)
		return false
	}
	/*
		m := &MedicalRecord{}
		err0 := row.Scan(&m.Groups, &m.SubjectMark, &m.Name, &m.NameInitials, &m.CaseNumber, &m.Sex, &m.Nation, &m.Diseases, &m.MedicalHistory, &m.NativePlace, &m.Diagnose, &m.Researcher, &m.Organization, &m.Addition1, &m.Addition2, &m.Addition3, &m.Status, &m.EntryTime, &m.BaseTime, &m.GatherTime)
		if err0 != nil {
			return false
		}
	*/
	return true
}

func SelectDBSingleRecord(DB *sql.DB, casenumer string) *MedicalRecord {
	sqlString := "select * from base_info where _CaseNumber = ?"
	stmt, _ := DB.Prepare(sqlString)
	row := stmt.QueryRow(casenumer)
	if row == nil {
		fmt.Println("未获取到该记录:", casenumer)
		return nil
	}
	m := &MedicalRecord{}
	err0 := row.Scan(&m.SubjectMark, &m.Researcher, &m.Organization, &m.Diseases, &m.CaseNumber, &m.GatherTime, &m.Groups, &m.Name, &m.NameInitials, &m.Sex, &m.Nation, &m.MedicalHistory, &m.NativePlace, &m.Diagnose, &m.Addition1, &m.Addition2, &m.Addition3, &m.Status, &m.EntryTime, &m.BaseTime)
	if err0 != nil {
		return nil
	}
	return m
}

func DeleteDB(DB *sql.DB, casenumer string) bool {
	sqlString0 := "delete  from insti_coop where _CaseNumber = ?"
	stmt0, _ := DB.Prepare(sqlString0)
	r0, err0 := stmt0.Exec(casenumer)
	if err0 != nil {
		fmt.Println("删除记录失败：", err0)
		return false
	}
	row_affect0, err1 := r0.RowsAffected()
	if err1 != nil {
		fmt.Println("受影响行数获取失败:", err1)
		return false
	}
	fmt.Println("受影响的行数：", row_affect0)
	sqlString01 := "delete  from policy where policy_id = ?"
	stmt01, _ := DB.Prepare(sqlString01)
	r01, err01 := stmt01.Exec(casenumer)
	if err01 != nil {
		fmt.Println("删除记录失败：", err01)
		return false
	}
	row_affect01, err11 := r01.RowsAffected()
	if err11 != nil {
		fmt.Println("受影响行数获取失败:", err11)
		return false
	}
	fmt.Println("受影响的行数：", row_affect01)
	sqlString1 := "delete  from base_info where _CaseNumber = ?"
	stmt1, _ := DB.Prepare(sqlString1)
	r1, err2 := stmt1.Exec(casenumer)
	if err2 != nil {
		fmt.Println("删除记录失败：", err2)
		return false
	}
	row_affect1, err3 := r1.RowsAffected()
	if err3 != nil {
		fmt.Println("受影响行数获取失败:", err3)
		return false
	}
	fmt.Println("受影响的行数：", row_affect1)
	return true
}

func InsertDB2Insti(DB *sql.DB, casenumber string) bool {
	fmt.Println(casenumber)
	var organization string
	SQLString := "select _Organization from base_info where _CaseNumber='" + casenumber + "'"
	err := DB.QueryRow(SQLString).Scan(&organization)
	if err == sql.ErrNoRows {
		return false
	} else {
		fmt.Println(organization)
		SQLString3 := "insert into insti_coop(_CaseNumber,insti_name)values(?,?)"
		_, err := DB.Exec(SQLString3, casenumber, organization)
		if err != nil {
			fmt.Println("err")
			return false
		} else {
			return true
		}
	}
}

func UpdateDB(DB *sql.DB, data []string) bool {
	sqlString := "update base_info set _Diseases = ?, _Groups = ?, _Diagnose = ? where _CaseNumber = ?;"
	r, err0 := DB.Exec(sqlString, data[2], data[3], data[4], data[0])
	fmt.Println(data)
	if err0 != nil {
		fmt.Println("修改失败：", err0)
		return false
	}
	//受影响的行数
	row_affect, err1 := r.RowsAffected()
	if err1 != nil {
		fmt.Println("受影响行数获取失败:", err1)
		return false
	}
	fmt.Println("受影响的行数：", row_affect)
	return true
}

// 定义返回的时间格式
var returnTimeType string

func ReturnTime(t int32) string {
	if t == 1 {
		returnTimeType = "2006-01-02"
	} else if t == 2 {
		returnTimeType = "2006-01-02 15:03:04"
	}
	now := time.Now()
	seconds := time.Unix(now.Unix(), 0)
	timeString := seconds.Format(returnTimeType)
	// 确定输出格式为string
	// fmt.Printf("%T\n", timeString)
	// 输出 时间戳，完整时间，最后返回内容
	// fmt.Println(now.Unix(), seconds, timeString)
	return timeString
}

// 返回hash——这个先放弃
/*
func hash(a Date2DB, t string) uint32 {
	baseString := []string{a.Groups, a.SubjectMark, a.Diseases, a.Researcher, a.Organization, ReturnTime(2)}
	s := strings.Join(baseString, "")
	h := fnv.New32a()
	h.Write([]byte(s))
	fmt.Println(h.Sum32())
	return h.Sum32()
}
*/

// CheckMobile 检验手机号
func judge_phone(phone string) bool {
	// 匹配规则
	// ^1第一位为一
	// [345789]{1} 后接一位345789 的数字
	// \\d \d的转义 表示数字 {9} 接9位
	// $ 结束符
	regRuler := "^1[345789]{1}\\d{9}$"

	// 正则调用规则
	reg := regexp.MustCompile(regRuler)

	// 返回 MatchString 是否匹配
	return reg.MatchString(phone)
}

// 判断手机号是否注册
func check_phone(DB *sql.DB, phone_num string) bool {
	sql := "SELECT phone_number FROM login"
	data := queryDB(DB, sql)
	for _, phone := range data {
		if phone == phone_num {
			return true
		}
	}
	return false
}

// 平台注册阶段
func CertificationPhone(DB *sql.DB, username string) (bool, int) {

	// if judge_phone(username) == false {
	// 	return false, 0
	// }
	if check_phone(DB, username) == true {
		return true, 1
	}
	return false, 2
}

// 效验18位身份证
func IsValidCitizenNo18(citizenNo18 []byte) bool {
	nLen := len(citizenNo18)
	if nLen != 18 {
		return false
	}

	nSum := 0
	for i := 0; i < nLen-1; i++ {
		n, _ := strconv.Atoi(string((citizenNo18)[i]))
		nSum += n * weight[i]
	}
	mod := nSum % 11
	if valid_value[mod] == (citizenNo18)[17] {
		return true
	}

	return false
}

func IsLeapYear(nYear int) bool {
	if nYear <= 0 {
		return false
	}

	if (nYear%4 == 0 && nYear%100 != 0) || nYear%400 == 0 {
		return true
	}

	return false
}

// 生日日期格式效验
func CheckBirthdayValid(nYear, nMonth, nDay int) bool {
	if nYear < 1900 || nMonth <= 0 || nMonth > 12 || nDay <= 0 || nDay > 31 {
		return false
	}

	curYear, curMonth, curDay := time.Now().Date()
	if nYear == curYear {
		if nMonth > int(curMonth) {
			return false
		} else if nMonth == int(curMonth) && nDay > curDay {
			return false
		}
	}

	if nMonth == 2 {
		if IsLeapYear(nYear) {
			if nDay > 29 {
				return false
			}
		} else if nDay > 28 {
			return false
		}
	} else if nMonth == 4 || nMonth == 6 || nMonth == 9 || nMonth == 11 {
		if nDay > 30 {
			return false
		}
	}

	return true
}

// 身份号码效验
func CheckProvinceValid(citizenNo []byte) bool {
	provinceCode := make([]byte, 0)
	provinceCode = append(provinceCode, citizenNo[:2]...)
	provinceStr := string(provinceCode)

	for i := range valid_province {
		if provinceStr == i {
			return true
		}
	}

	return false
}

// 效验有效地身份证号码
func IsValidCitizenNo(citizenNo []byte) bool {
	if !IsValidCitizenNo18(citizenNo) {
		return false
	}

	for i, v := range citizenNo {
		n, _ := strconv.Atoi(string(v))
		if n >= 0 && n <= 9 {
			continue
		}

		if v == 'X' && i == 16 {
			continue
		}

		return false
	}

	if !CheckProvinceValid(citizenNo) {
		return false
	}

	nYear, _ := strconv.Atoi(string((citizenNo)[6:10]))
	tmp := []byte{}
	tmp = append(tmp, citizenNo...)
	nMonth, _ := strconv.Atoi(string((tmp)[10:12]))
	//fmt.Println(nMonth)
	nDay, _ := strconv.Atoi(string((tmp)[12:14]))
	if !CheckBirthdayValid(nYear, nMonth, nDay) {
		return false
	}

	return true
}

func judge_identity(identity string) bool {
	id_card := []byte{}
	id_card = *(*[]byte)(unsafe.Pointer(&identity))
	//fmt.Println(id_card)
	return IsValidCitizenNo(id_card)
}

func check_identity(DB *sql.DB, identity string) bool {
	sql := "SELECT identity FROM login"
	data := queryDB(DB, sql)
	for _, id := range data {
		if id == identity {
			return true
		}
	}
	return false
}

// 实名认证
func CertificationId(DB *sql.DB, identity string) (bool, int) {

	if judge_identity(identity) == false {
		return false, 0
	}
	if check_identity(DB, identity) == true {
		return true, 1
	}
	return false, 2
}

// interface{}转string
func Strval(value interface{}) string {
	// interface 转 string
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

// // 设置获取上链后的区块信息
// 传入参数是block，操作类型，主体和客体，返回 block
func Getinfo2Block(DB *sql.DB, block *common.Block, actionType string, objectID string, subjectID string, ChaincodeName string, isSuccess string, eventIndex int) Block {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		fmt.Println("LoadLocation error: " + err.Error())
	}
	BlockHeader := block.GetHeader()
	blockinfo := Block{
		NumberBlock:  strconv.FormatUint(BlockHeader.Number, 10),
		HashBlock:    base64.StdEncoding.EncodeToString(BlockHeader.DataHash)[:20], //因长度过长，限制为20位
		GenerateTime: time.Now().In(loc).Format("2006-01-02 15:04:05"),
		ActionType:   actionType,
		ObjectID:     objectID, // 写反了，这里是用户
		SubjectID:    subjectID,
	}
	GenerateOperationReocrd(DB, eventIndex, blockinfo.ObjectID, blockinfo.SubjectID, ChaincodeName, isSuccess, "T")
	return blockinfo
}

// 传入新创建的block和blockinfo，进行顺序替换
func BlockJust3(thisblock Block, thisblockInto GetThisBlockInto) GetThisBlockInto {
	thisblockInto.ThirdBlock = thisblockInto.SecondBlock //第2个设置为第3个
	thisblockInto.SecondBlock = thisblockInto.FirstBlock //第1个设置为第2个
	thisblockInto.FirstBlock = thisblock                 //第1个设置为 thisblock
	return thisblockInto

}

// 生成并向数据库插入操作记录
// ChaincodeName 用于判断操作类型
func GenerateOperationReocrd(DB *sql.DB, RecordID int, UserID string, CaseNumber string, ChaincodeName string, IsSuccess string, IsUpload string) {
	TimeStr := time.Now().Format("2006-01-02 15:04:05")
	var DataType, ActionType string
	if ChaincodeName == "InitUploadMed" {
		DataType = "医疗记录"
		ActionType = "初始化"
	} else if ChaincodeName == "GetInitMedInfo" {
		DataType = "医疗记录"
		ActionType = "查看"
	} else if ChaincodeName == "AccessMedicalRecord" {
		DataType = "溯源结果"
		ActionType = "溯源"
	} else if ChaincodeName == "UploadMedicalRecord" {
		DataType = "医疗记录"
		ActionType = "创建"
	} else if ChaincodeName == "ReadMedicalRecord" {
		DataType = "医疗记录"
		ActionType = "访问"
	} else if ChaincodeName == "DeleteMedicalRecord" {
		DataType = "医疗记录"
		ActionType = "删除"
	} else if ChaincodeName == "AuditMedicalRecord" {
		DataType = "审计结果"
		ActionType = "审计"
	} else if ChaincodeName == "UpdateMedicalRecord" {
		DataType = "医疗记录"
		ActionType = "更新"
	}
	SQLstring := "insert into operation_record (OperationRecordID, UserID, MedicalRecordID, DataType, ActionType, IsSuccess, IsUpload, _GatherTime) values (?,?,?,?,?,?,?,?)"
	_, err := DB.Exec(SQLstring, RecordID, UserID, CaseNumber, DataType, ActionType, IsSuccess, IsUpload, TimeStr)
	if err != nil {
		fmt.Println(err.Error())
	}
}
